package ru.fadeev.crammer.ui.treetable;

/*
 * @(#)TreeTableModelAdapter.java	1.2 98/10/27
 *
 * Copyright 1997, 1998 by Sun Microsystems, Inc.,
 * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Sun Microsystems, Inc. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Sun.
 */

import javax.swing.JTree;
//import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
import javax.swing.tree.TreePath;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.event.TableModelListener;
import javax.swing.event.TableModelEvent;


/**
 * This is a wrapper class takes a TreeTableModel and implements 
 * the table model interface. The implementation is trivial, with 
 * all of the event dispatching support provided by the superclass: 
 * the AbstractTableModel. 
 *
 * @version 1.2 10/27/98
 *
 * @author Philip Milne
 * @author Scott Violet
 */
public class TreeTableModelAdapter extends AbstractTableModel
{
    public JTree tree;
    TreeTableModel treeTableModel;
    TableModel source = this;

    public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree _tree) {
        this.tree = _tree;
        this.treeTableModel = treeTableModel;

        tree.addTreeExpansionListener(new TreeExpansionListener() {
		    // Don't use fireTableRowsInserted() here; the selection model
		    // would get updated twice. 
		    public void treeExpanded(TreeExpansionEvent event) {  
		    	fireTableDataChanged(); 
		    }
		    
	        public void treeCollapsed(TreeExpansionEvent event) {  
	        	fireTableDataChanged(); 
		    }
        });

		// Install a TreeModelListener that can update the table when
		// tree changes. We use delayedFireTableDataChanged as we can
		// not be guaranteed the tree will have finished processing
		// the event before us.
		treeTableModel.addTreeModelListener(new TreeModelListener() {
		    public void treeNodesChanged(TreeModelEvent treeEvent) {
		    	//delayedFireTableDataChanged();
		    	//fireTableDataChanged();
		        Object[] listeners = listenerList.getListenerList();
		        // Process the listeners last to first, notifying
		        // those that are interested in this event
		        TableModelEvent tableEvent = null;
		        TreePath parent = treeEvent.getTreePath();
		        Object[] children = treeEvent.getChildren();
		        if(children == null) {
		        	fireTableDataChanged();
		        } else {
			        for(int j = 0; j < children.length; j++) {
			        	int rowIndex = tree.getRowForPath(
			        		parent.pathByAddingChild(children[j]));
			        	if(rowIndex >= 0) {
					        for (int i = listeners.length-2; i>=0; i-=2) {
					            if (listeners[i]==TableModelListener.class) {		            	
					                if (tableEvent == null)
					                	tableEvent = new TableModelEvent(source, rowIndex);
					            
					                ((TableModelListener)listeners[i+1]).tableChanged(tableEvent);
					            }          
					        }
			        	}
			        }
		        }
		    }
	
		    /*
		     * Works when only one node added to the end
		     * @see javax.swing.event.TreeModelListener#treeNodesInserted(javax.swing.event.TreeModelEvent)
		     */
		    public void treeNodesInserted(TreeModelEvent treeEvent) {
		        Object[] listeners = listenerList.getListenerList();
		        TableModelEvent tableEvent = null;
		        TreePath parent = treeEvent.getTreePath();
		        Object[] children = treeEvent.getChildren();
		        for(int j = 0; j < children.length; j++) {
		        	int rowIndex = tree.getRowForPath(
		        		parent.pathByAddingChild(children[j]));
		        	if(rowIndex < 0) {
		        		rowIndex = tree.getRowCount();	
		        	}
			        for (int i = listeners.length-2; i>=0; i-=2) {
			            if (listeners[i]==TableModelListener.class) {		            	
			                if (tableEvent == null)
			                	tableEvent = new TableModelEvent(source, 
			                			rowIndex, rowIndex, 
			                			TableModelEvent.ALL_COLUMNS, 
			                			TableModelEvent.INSERT);	            
			                ((TableModelListener)listeners[i+1]).tableChanged(tableEvent);
			            }          
		        	}
		        }
		    }
	
		    public void treeNodesRemoved(TreeModelEvent treeEvent) {
		        Object[] listeners = listenerList.getListenerList();
		        TableModelEvent tableEvent = null;
		        TreePath parent = treeEvent.getTreePath();
		        Object[] children = treeEvent.getChildren();
		        for(int j = 0; j < children.length; j++) {
		        	int rowIndex = tree.getRowForPath(
		        		parent.pathByAddingChild(children[j]));
		        	if(rowIndex < 0) {
		        		rowIndex = tree.getRowCount();	
		        	}
			        for (int i = listeners.length-2; i>=0; i-=2) {
			            if (listeners[i]==TableModelListener.class) {		            	
			                if (tableEvent == null)
			                	tableEvent = new TableModelEvent(source, 
			                			rowIndex, rowIndex, 
			                			TableModelEvent.ALL_COLUMNS, 
			                			TableModelEvent.DELETE);	            
			                ((TableModelListener)listeners[i+1]).tableChanged(tableEvent);
			            }          
			        }
		        }
		    }
	
		    public void treeStructureChanged(TreeModelEvent e) {
		    	fireTableDataChanged();
		    }
		});
    }

    // Wrappers, implementing TableModel interface. 

    public int getColumnCount() {
    	return treeTableModel.getColumnCount();
    }

    public String getColumnName(int column) {
    	return treeTableModel.getColumnName(column);
    }

    public Class<?> getColumnClass(int column) {
    	return treeTableModel.getColumnClass(column);
    }

    public int getRowCount() {
    	return tree.getRowCount();
    }

    protected Object nodeForRow(int row) {
		TreePath treePath = tree.getPathForRow(row);
		return treePath.getLastPathComponent();         
    }

    public Object getValueAt(int row, int column) {
    	return treeTableModel.getValueAt(nodeForRow(row), column);
    }

    public boolean isCellEditable(int row, int column) {
         return treeTableModel.isCellEditable(nodeForRow(row), column); 
    }

    public void setValueAt(Object value, int row, int column) {
    	treeTableModel.setValueAt(value, nodeForRow(row), column);
    }

    /**
     * Invokes fireTableDataChanged after all the pending events have been
     * processed. SwingUtilities.invokeLater is used to handle this.
     */
    protected void delayedFireTableDataChanged() {
    	//fireTableDataChanged();
		//SwingUtilities.invokeLater(new Runnable() {
		//    public void run() {
		//	fireTableDataChanged();
		//   }
		//});
    }
}

